home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / fluid / Fluid_Image.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-07-31  |  10.5 KB  |  422 lines

  1. //
  2. // "$Id: Fluid_Image.cxx,v 1.7.2.1 1999/07/31 08:00:08 bill Exp $"
  3. //
  4. // Pixmap label support for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-1999 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  24. //
  25.  
  26. #include <FL/Fl.H>
  27. #include <FL/Fl_Widget.H>
  28. #include "Fl_Type.h"
  29. #include "Fluid_Image.h"
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <errno.h>
  33. #include <ctype.h>
  34. #include <stdlib.h>
  35. #include <FL/filename.H>
  36.  
  37. extern void goto_source_dir(); // in fluid.C
  38. extern void leave_source_dir(); // in fluid.C
  39.  
  40. ////////////////////////////////////////////////////////////////
  41. #include <FL/Fl_Pixmap.H>
  42.  
  43. class pixmap_image : public Fluid_Image {
  44. protected:
  45.   Fl_Pixmap *p;
  46.   int *linelength;
  47. public:
  48.   pixmap_image(const char *name, FILE *);
  49.   ~pixmap_image();
  50.   virtual void label(Fl_Widget *); // set the label of this widget
  51.   virtual void write_static();
  52.   virtual void write_code();
  53.   static int test_file(char *buffer);
  54. };
  55.  
  56. int pixmap_image::test_file(char *buffer) {
  57.   return (strstr(buffer,"/* XPM") != 0);
  58. }
  59.  
  60. void pixmap_image::label(Fl_Widget *o) {
  61.   if (p) p->label(o);
  62. }
  63.  
  64. static int pixmap_header_written;
  65.  
  66. void pixmap_image::write_static() {
  67.   if (!p) return;
  68.   write_c("\n");
  69.   if (pixmap_header_written != write_number) {
  70.     write_c("#include <FL/Fl_Pixmap.H>\n");
  71.     pixmap_header_written = write_number;
  72.   }
  73.   write_c("static unsigned char *%s[] = {\n",
  74.       unique_id(this, "image", filename_name(name()), 0));
  75.   int l;
  76.   for (l = 0; p->data[l]; l++) {
  77.     if (l) write_c(",\n");
  78.     write_c("(unsigned char*)\n");
  79.     write_cstring(p->data[l],linelength[l]);
  80.   }
  81.   write_c("\n};\n");
  82.   write_c("static Fl_Pixmap %s(%s);\n",
  83.       unique_id(this, "pixmap", filename_name(name()), 0),
  84.       unique_id(this, "image", filename_name(name()), 0));
  85. }
  86.  
  87. void pixmap_image::write_code() {
  88.   if (!p) return;
  89.   write_c("%s%s.label(o);\n", indent(),
  90.       unique_id(this, "pixmap", filename_name(name()), 0));
  91. }
  92.  
  93. static int hexdigit(int x) {
  94.   if (isdigit(x)) return x-'0';
  95.   if (isupper(x)) return x-'A'+10;
  96.   if (islower(x)) return x-'a'+10;
  97.   return 20;
  98. }
  99.  
  100. #define MAXSIZE 2048
  101.  
  102. pixmap_image::pixmap_image(const char *name, FILE *f) : Fluid_Image(name) {
  103.   if (!f) return; // for subclasses
  104.   // read all the c-strings out of the file:
  105.   char *data[MAXSIZE+1];
  106.   int length[MAXSIZE+1];
  107.   char buffer[MAXSIZE+20];
  108.   int i = 0;
  109.   while (i < MAXSIZE && fgets(buffer,MAXSIZE+20,f)) {
  110.     if (buffer[0] != '\"') continue;
  111.     char *p = buffer;
  112.     char *q = buffer+1;
  113.     while (*q != '\"' && p < buffer+MAXSIZE) {
  114.       if (*q == '\\') switch (*++q) {
  115.       case '\n':
  116.     fgets(q,(buffer+MAXSIZE+20)-q,f); break;
  117.       case 0:
  118.     break;
  119.       case 'x': {
  120.     q++;
  121.     int n = 0;
  122.     for (int x = 0; x < 3; x++) {
  123.       int d = hexdigit(*q);
  124.       if (d > 15) break;
  125.       n = (n<<4)+d;
  126.       q++;
  127.     }
  128.     *p++ = n;
  129.       } break;
  130.       default: {
  131.     int c = *q++;
  132.     if (c>='0' && c<='7') {
  133.       c -= '0';
  134.       for (int x=0; x<2; x++) {
  135.         int d = hexdigit(*q);
  136.         if (d>7) break;
  137.         c = (c<<3)+d;
  138.         q++;
  139.       }
  140.     }
  141.     *p++ = c;
  142.       } break;
  143.       } else {
  144.     *p++ = *q++;
  145.       }
  146.     }
  147.     *p++ = 0;
  148.     data[i] = new char[p-buffer];
  149.     memcpy(data[i],buffer,p-buffer);
  150.     length[i] = p-buffer-1;
  151.     i++;
  152.   }
  153.   data[i++] = 0; // put a null at the end
  154.  
  155.   char** real_data = new char*[i];
  156.   linelength = new int[i];
  157.   while (i--) {real_data[i] = data[i]; linelength[i] = length[i];}
  158.   p = new Fl_Pixmap(real_data);
  159. }
  160.  
  161. pixmap_image::~pixmap_image() {
  162.   if (p && p->data) {
  163.     char** real_data = (char**)(p->data);
  164.     for (int i = 0; real_data[i]; i++) delete[] real_data[i];
  165.     delete[] real_data;
  166.   }
  167.   delete[] linelength;
  168.   delete p;
  169. }
  170.  
  171. ////////////////////////////////////////////////////////////////
  172.  
  173. class gif_image : public pixmap_image {
  174. public:
  175.   gif_image(const char *name, FILE *);
  176.   ~gif_image();
  177.   static int test_file(char *buffer);
  178. };
  179.  
  180. int gif_image::test_file(char *buffer) {
  181.   return !strncmp(buffer,"GIF",3);
  182. }
  183.  
  184. // function in gif.C:
  185. int gif2xpm(
  186.     const char *infname,// filename for error messages
  187.     FILE *GifFile,    // file to read
  188.     char*** datap,    // return xpm data here
  189.     int** lengthp,    // return line lengths here
  190.     int inumber        // which image in movie (0 = first)
  191. );
  192.  
  193. gif_image::gif_image(const char *name, FILE *f) : pixmap_image(name,0) {
  194.   char** datap;
  195.   if (gif2xpm(name,f,&datap,&linelength,0)) {
  196.     p = new Fl_Pixmap(datap);
  197.   } else
  198.     p = 0;
  199. }
  200.  
  201. gif_image::~gif_image() {
  202.   if (p && p->data) {
  203.     char** real_data = (char**)(p->data);
  204.     for (int i = 0; i < 3; i++) delete[] real_data[i];
  205.     delete[] real_data;
  206.     p->data = 0;
  207.   }
  208. }
  209.  
  210. ////////////////////////////////////////////////////////////////
  211. #include <FL/Fl_Bitmap.H>
  212.  
  213. class bitmap_image : public Fluid_Image {
  214.   Fl_Bitmap *p;
  215. public:
  216.   ~bitmap_image();
  217.   bitmap_image(const char *name, FILE *);
  218.   virtual void label(Fl_Widget *); // set the label of this widget
  219.   virtual void write_static();
  220.   virtual void write_code();
  221.   static int test_file(char *buffer);
  222. };
  223.  
  224. // bad test, always do this last!
  225. int bitmap_image::test_file(char *buffer) {
  226.   return (strstr(buffer,"#define ") != 0);
  227. }
  228.  
  229. void bitmap_image::label(Fl_Widget *o) {
  230.   if (p) p->label(o); else o->labeltype(FL_NORMAL_LABEL);
  231. }
  232.  
  233. static int bitmap_header_written;
  234.  
  235. void bitmap_image::write_static() {
  236.   if (!p) return;
  237.   write_c("\n");
  238.   if (bitmap_header_written != write_number) {
  239.     write_c("#include <FL/Fl_Bitmap.H>\n");
  240.     bitmap_header_written = write_number;
  241.   }
  242. #if 0 // older one
  243.   write_c("static unsigned char %s[] = {  \n",
  244.       unique_id(this, "bits", filename_name(name()), 0));
  245.   int n = ((p->w+7)/8)*p->h;
  246.   int linelength = 0;
  247.   for (int i = 0; i < n; i++) {
  248.     if (i) {write_c(","); linelength++;}
  249.     if (linelength > 75) {write_c("\n"); linelength=0;}
  250.     int v = p->array[i];
  251.     write_c("%d",v);
  252.     linelength++; if (v>9) linelength++; if (v>99) linelength++;
  253.   }
  254.   write_c("\n};\n");
  255. #else // this seems to produce slightly shorter c++ files
  256.   write_c("static unsigned char %s[] =\n",
  257.       unique_id(this, "bits", filename_name(name()), 0));
  258.   int n = ((p->w+7)/8)*p->h;
  259.   write_cstring((const char*)(p->array), n);
  260.   write_c(";\n");
  261. #endif
  262.   write_c("static Fl_Bitmap %s(%s, %d, %d);\n",
  263.       unique_id(this, "bitmap", filename_name(name()), 0),
  264.       unique_id(this, "bits", filename_name(name()), 0),
  265.       p->w, p->h);
  266. }
  267.  
  268. void bitmap_image::write_code() {
  269.   if (!p) return;
  270.   write_c("%s%s.label(o);\n", indent(),
  271.       unique_id(this, "bitmap", filename_name(name()), 0));
  272. }
  273.  
  274. bitmap_image::bitmap_image(const char *name, FILE *f) : Fluid_Image(name) {
  275.   p = 0; // if any problems with parse we exit with this zero
  276.   char buffer[1024];
  277.   char junk[1024];
  278.   int wh[2]; // width and height
  279.   int i;
  280.   for (i = 0; i<2; i++) {
  281.     for (;;) {
  282.       if (!fgets(buffer,1024,f)) return;
  283.       int r = sscanf(buffer,"#define %s %d",junk,&wh[i]);
  284.       if (r >= 2) break;
  285.     }
  286.   }
  287.   // skip to data array:
  288.   for (;;) {
  289.     if (!fgets(buffer,1024,f)) return;
  290.     if (!strncmp(buffer,"static ",7)) break;
  291.   }
  292.   int n = ((wh[0]+7)/8)*wh[1];
  293.   uchar *data = new uchar[n];
  294.   // read the data:
  295.   i = 0;
  296.   for (;i<n;) {
  297.     if (!fgets(buffer,1024,f)) return;
  298.     const char *a = buffer;
  299.     while (*a && i<n) {
  300.       int t;
  301.       if (sscanf(a," 0x%x",&t)>0) data[i++] = t;
  302.       while (*a && *a++ != ',');
  303.     }
  304.   }
  305.   p = new Fl_Bitmap(data,wh[0],wh[1]);
  306. }
  307.  
  308. bitmap_image::~bitmap_image() {
  309.   if (p) {
  310.     delete[] (uchar*)(p->array);
  311.     delete p;
  312.   }
  313. }
  314.  
  315. ////////////////////////////////////////////////////////////////
  316.  
  317. static Fluid_Image** images; // sorted list
  318. static int numimages;
  319. static int tablesize;
  320.  
  321. Fluid_Image* Fluid_Image::find(const char *name) {
  322.   if (!name || !*name) return 0;
  323.  
  324.   // first search to see if it exists already:
  325.   int a = 0;
  326.   int b = numimages;
  327.   while (a < b) {
  328.     int c = (a+b)/2;
  329.     int i = strcmp(name,images[c]->name_);
  330.     if (i < 0) b = c;
  331.     else if (i > 0) a = c+1;
  332.     else return images[c];
  333.   }
  334.  
  335.   // no, so now see if the file exists:
  336.  
  337.   goto_source_dir();
  338.   FILE *f = fopen(name,"rb");
  339.   if (!f) {
  340.     read_error("%s : %s",name,strerror(errno));
  341.     leave_source_dir();
  342.     return 0;
  343.   }
  344.  
  345.   Fluid_Image *ret;
  346.  
  347.   // now see if we can identify the type, by reading in some data
  348.   // and asking all the types we know about:
  349.  
  350.   char buffer[1025];
  351.   fread(buffer, 1, 1024, f);
  352.   rewind(f);
  353.   buffer[1024] = 0; // null-terminate so strstr() works
  354.  
  355.   if (pixmap_image::test_file(buffer)) {
  356.     ret = new pixmap_image(name,f);
  357.   } else if (gif_image::test_file(buffer)) {
  358.     ret = new gif_image(name,f);
  359.   } else if (bitmap_image::test_file(buffer)) {
  360.     ret = new bitmap_image(name,f);
  361.   } else {
  362.     ret = 0;
  363.     read_error("%s : unrecognized image format", name);
  364.   }
  365.   fclose(f);
  366.   leave_source_dir();
  367.   if (!ret) return 0;
  368.  
  369.   // make a new entry in the table:
  370.   numimages++;
  371.   if (numimages > tablesize) {
  372.     tablesize = tablesize ? 2*tablesize : 16;
  373.     images = (Fluid_Image**)realloc(images, tablesize*sizeof(Fluid_Image*));
  374.   }
  375.   for (b = numimages-1; b > a; b--) images[b] = images[b-1];
  376.   images[a] = ret;
  377.  
  378.   return ret;
  379. }
  380.  
  381. Fluid_Image::Fluid_Image(const char *name) {
  382.   name_ = strdup(name);
  383.   written = 0;
  384.   refcount = 0;
  385. }
  386.  
  387. void Fluid_Image::increment() {
  388.   ++refcount;
  389. }
  390.  
  391. void Fluid_Image::decrement() {
  392.   --refcount;
  393.   if (refcount > 0) return;
  394.   delete this;
  395. }
  396.  
  397. Fluid_Image::~Fluid_Image() {
  398.   int a;
  399.   for (a = 0;; a++) if (images[a] == this) break;
  400.   numimages--;
  401.   for (; a < numimages; a++) images[a] = images[a+1];
  402.   free((void*)name_);
  403. }
  404.  
  405. ////////////////////////////////////////////////////////////////
  406.  
  407. #include <FL/fl_file_chooser.H>
  408.  
  409. const char *ui_find_image_name;
  410. Fluid_Image *ui_find_image(const char *oldname) {
  411.   goto_source_dir();
  412.   const char *name = fl_file_chooser("Image","*.{bm|xbm|xpm|gif}",oldname);
  413.   ui_find_image_name = name;
  414.   Fluid_Image *ret = (name && *name) ? Fluid_Image::find(name) : 0;
  415.   leave_source_dir();
  416.   return ret;
  417. }
  418.  
  419. //
  420. // End of "$Id: Fluid_Image.cxx,v 1.7.2.1 1999/07/31 08:00:08 bill Exp $".
  421. //
  422.